#include "luaglue.h"
#include "macro.h"
#include "color.h"
#include "misc.h"
#include "message.h"
#include "logger.h"

#include "sha1.h"

#define MAP_FUNCTION(name)      {(char *)#name, name}
#define END_MAP                 {NULL, NULL}

#define wrongArgs(state)            wrongArgsReal(state, __FUNCTION__)
#define invalidData(state, arg)     invalidDataReal(state, arg, __FUNCTION__)

#define DEPRECATED()		static bool __firstRun = true; \
	if( __firstRun ) \
	{ \
		__firstRun = false; \
		Logger::instance()->add("Function \'%s\' is deprecated.\n", \
		__FUNCTION__); \
	}

enum MMType{
	T_NIL = 0x1,
	T_NUMBER = 0x2,
	T_STRING = 0x4,
	T_BOOLEAN = 0x8,
	T_TABLE = 0x10,
	T_FUNCTION = 0x20,
	T_THREAD = 0x40,
	T_USERDATA = 0x80,

	T_NONNIL = T_NUMBER | T_STRING | T_BOOLEAN | T_TABLE | T_FUNCTION | T_THREAD | T_USERDATA,
	T_ANY = T_NIL | T_NONNIL
};

const char *metatable_handle = "MicroMacro.handle";
const char *metatable_hdc = "MicroMacro.hdc";
const char *metatable_netcon = "MicroMacro.netcon";
const char *metatable_int64 = "MicroMacro.int64";
const char *metatable_audioresource = "MicroMacro.audioresource";

void wrongArgsReal(lua_State *s, const char *name)
{
    luaL_error(s, "Wrong number of parameters supplied to %s().\n", name);
}

void invalidDataReal(lua_State *s, int arg, const char *name)
{
    luaL_argerror(s, arg, NULL);
}

void invalidType(lua_State *s, int arg, const char *expected)
{
	luaL_typerror(s, arg, expected);
}

int luaL_typerror (lua_State *s, int narg, const char *tname)
{
	const char *msg = lua_pushfstring(s, "%s expected, got %s", tname,
		luaL_typename(s, narg));

	return luaL_argerror(s, narg, msg);
}


int checkType(lua_State *s, int acceptableTypes, int arg)
{
	int ok = false;
	std::vector<std::string> acceptableTypeNames;

	// Check each type
	if( acceptableTypes & T_NIL )
	{
		acceptableTypeNames.push_back("nil");
		if( lua_isnil(s, arg) )
			ok = true;
	}

	if( acceptableTypes & T_NUMBER )
	{
		acceptableTypeNames.push_back("number");
		if( lua_isnumber(s, arg) )
			ok = true;
	}

	if( acceptableTypes & T_STRING )
	{
		acceptableTypeNames.push_back("string");
		if( lua_isstring(s, arg) )
			ok = true;
	}

	if( acceptableTypes & T_BOOLEAN )
	{
		acceptableTypeNames.push_back("boolean");
		if( lua_isboolean(s, arg) )
			ok = true;
	}

	if( acceptableTypes & T_TABLE )
	{
		acceptableTypeNames.push_back("table");
		if( lua_istable(s, arg) )
			ok = true;
	}

	if( acceptableTypes & T_FUNCTION )
	{
		acceptableTypeNames.push_back("function");
		if( lua_isfunction(s, arg) )
			ok = true;
	}

	if( acceptableTypes & T_THREAD )
	{
		acceptableTypeNames.push_back("thread");
		if( lua_isthread(s, arg) )
			ok = true;
	}

	if( acceptableTypes & T_USERDATA )
	{
		acceptableTypeNames.push_back("userdata");
		if( lua_isuserdata(s, arg) )
			ok = true;
	}


	if( !ok )
	{
		char expected[256];
		strcpy((char*)expected, "unknown");

		for(unsigned int i = 0; i < acceptableTypeNames.size(); i++)
		{
			if( i == 0 )
				strncpy((char*)expected, acceptableTypeNames[i].c_str(), 255);
			else if( i == acceptableTypeNames.size() - 1 )
			{
				strncat((char*)expected, " or ", 255);
				strncat((char*)expected, acceptableTypeNames[i].c_str(), 255);
			} else
			{
				strncat((char*)expected, ", ", 255);
				strncat((char*)expected, acceptableTypeNames[i].c_str(), 255);
			}
		}

		luaL_typerror(s, arg, expected);
	}

	return 0;
}

/* Read a LARGE_INTEGER from the Lua stack */
LARGE_INTEGER lua_toint64(lua_State *lstate, int index)
{
	LARGE_INTEGER retval;

	lua_pushvalue(lstate, index); // Copy it so we don't screw up the stack

	lua_pushstring(lstate, "high");
	lua_gettable(lstate, -2);
	retval.HighPart = (unsigned long)lua_tonumber(lstate, -1);
	lua_pop(lstate, 1);

	lua_pushstring(lstate, "low");
	lua_gettable(lstate, -2);
	retval.LowPart = (unsigned long)lua_tonumber(lstate, -1);
	lua_pop(lstate, 1);

	lua_pop(lstate, 1); // Pop our copy off the stack

	return retval;
}

void registerGlues(lua_State *lstate)
{
    FunctionMap funcMap[] =
    {
        MAP_FUNCTION(mouseSetDelay),
        MAP_FUNCTION(mouseMove),
        MAP_FUNCTION(mouseSet),
        MAP_FUNCTION(mouseLHold),
        MAP_FUNCTION(mouseLRelease),
        MAP_FUNCTION(mouseLClick),
        MAP_FUNCTION(mouseMHold),
        MAP_FUNCTION(mouseMRelease),
        MAP_FUNCTION(mouseMClick),
        MAP_FUNCTION(mouseRHold),
        MAP_FUNCTION(mouseRRelease),
        MAP_FUNCTION(mouseRClick),
        MAP_FUNCTION(mouseWheelMove),
        MAP_FUNCTION(mouseGetPos),
        MAP_FUNCTION(keyboardSetDelay),
        MAP_FUNCTION(keyboardHold),
        MAP_FUNCTION(keyboardRelease),
        MAP_FUNCTION(keyboardPress),
        MAP_FUNCTION(keyPressed),
		MAP_FUNCTION(keyboardState),
        MAP_FUNCTION(keyPressedLocal),
        MAP_FUNCTION(keyboardType),
        MAP_FUNCTION(keyboardBufferClear),
        MAP_FUNCTION(getKeyName),
        MAP_FUNCTION(attach),
		MAP_FUNCTION(attachKeyboard),
		MAP_FUNCTION(attachMouse),
        MAP_FUNCTION(detach),
        MAP_FUNCTION(getAttachedHwnd),
        MAP_FUNCTION(openProcess),
        MAP_FUNCTION(closeProcess),
        MAP_FUNCTION(findProcess),
        MAP_FUNCTION(findProcessByExe),
        MAP_FUNCTION(findProcessByWindow),
		MAP_FUNCTION(getWindowParent),
        MAP_FUNCTION(findWindow),
        MAP_FUNCTION(findWindowList),
        MAP_FUNCTION(foregroundWindow),
        MAP_FUNCTION(getHwnd),
        MAP_FUNCTION(getWindowName),
		MAP_FUNCTION(getWindowClassName),
        MAP_FUNCTION(setWindowName),
        MAP_FUNCTION(windowValid),
        MAP_FUNCTION(windowRect),
        MAP_FUNCTION(openDC),
        MAP_FUNCTION(closeDC),
        MAP_FUNCTION(makeColor),
        MAP_FUNCTION(getR),
        MAP_FUNCTION(getG),
        MAP_FUNCTION(getB),
        MAP_FUNCTION(getPixel),
        MAP_FUNCTION(setPixel),
        MAP_FUNCTION(pixelSearch),
        MAP_FUNCTION(drawLine),
        MAP_FUNCTION(drawRect),
        MAP_FUNCTION(saveScreenshot),
		MAP_FUNCTION(getClipboard),
		MAP_FUNCTION(setClipboard),
        MAP_FUNCTION(showWindow),
		MAP_FUNCTION(setWindowPos),
        MAP_FUNCTION(findPatternInProcess),
		MAP_FUNCTION(getModuleAddress),
		MAP_FUNCTION(flashWindow),
		MAP_FUNCTION(getConsoleAttributes),
		MAP_FUNCTION(setConsoleAttributes),
        MAP_FUNCTION(getPath),
        MAP_FUNCTION(getExecutionPath),
        MAP_FUNCTION(setExecutionPath),
        MAP_FUNCTION(getFileName),
        MAP_FUNCTION(getFilePath),
        MAP_FUNCTION(getDirectory),
		MAP_FUNCTION(isDirectory),
        MAP_FUNCTION(memoryReadByte),
		MAP_FUNCTION(memoryReadUByte),
        MAP_FUNCTION(memoryReadShort),
		MAP_FUNCTION(memoryReadUShort),
        MAP_FUNCTION(memoryReadInt),
        MAP_FUNCTION(memoryReadUInt),
        MAP_FUNCTION(memoryReadFloat),
		MAP_FUNCTION(memoryReadDouble),
        MAP_FUNCTION(memoryReadString),
        MAP_FUNCTION(memoryReadUString),
        MAP_FUNCTION(memoryReadBytePtr),
		MAP_FUNCTION(memoryReadUBytePtr),
        MAP_FUNCTION(memoryReadShortPtr),
		MAP_FUNCTION(memoryReadUShortPtr),
        MAP_FUNCTION(memoryReadIntPtr),
        MAP_FUNCTION(memoryReadUIntPtr),
        MAP_FUNCTION(memoryReadFloatPtr),
		MAP_FUNCTION(memoryReadDoublePtr),
        MAP_FUNCTION(memoryReadStringPtr),
        MAP_FUNCTION(memoryReadUStringPtr),
        MAP_FUNCTION(memoryWriteByte),
        MAP_FUNCTION(memoryWriteShort),
        MAP_FUNCTION(memoryWriteInt),
        MAP_FUNCTION(memoryWriteFloat),
		MAP_FUNCTION(memoryWriteDouble),
		MAP_FUNCTION(memoryWriteString),
        MAP_FUNCTION(memoryWriteBytePtr),
        MAP_FUNCTION(memoryWriteShortPtr),
        MAP_FUNCTION(memoryWriteIntPtr),
        MAP_FUNCTION(memoryWriteFloatPtr),
		MAP_FUNCTION(memoryWriteDoublePtr),
		MAP_FUNCTION(memoryReadBatch),
        MAP_FUNCTION(netPushKey),
        MAP_FUNCTION(netOpenCon),
        MAP_FUNCTION(netListen),
        MAP_FUNCTION(netPollListen),
        MAP_FUNCTION(netConnect),
        MAP_FUNCTION(netConnectStatus),
        MAP_FUNCTION(netPollMessages),
        MAP_FUNCTION(netGetMessage),
        MAP_FUNCTION(netSendMessage),
		MAP_FUNCTION(netGetAddress),
        MAP_FUNCTION(netCloseCon),
        MAP_FUNCTION(newTimer),
        MAP_FUNCTION(removeTimer),
        MAP_FUNCTION(startTimer),
        MAP_FUNCTION(isTriggered),
        MAP_FUNCTION(getTime),
		MAP_FUNCTION(getTimerFrequency),
        MAP_FUNCTION(deltaTime),
		MAP_FUNCTION(ipcOpen),
		MAP_FUNCTION(ipcClose),
		MAP_FUNCTION(ipcSend),
		MAP_FUNCTION(soundPlay),
		MAP_FUNCTION(soundStop),
		MAP_FUNCTION(soundPause),
		MAP_FUNCTION(soundLoad),
		MAP_FUNCTION(soundSetLooping),
		MAP_FUNCTION(soundSetVolume),
		MAP_FUNCTION(soundGetState),
        MAP_FUNCTION(clearScreen),
        MAP_FUNCTION(rest),
        MAP_FUNCTION(setPriority),
        MAP_FUNCTION(logMessage),
        MAP_FUNCTION(logRaw),
        MAP_FUNCTION(getVersion),
        MAP_FUNCTION(setTextColor),
        MAP_FUNCTION(showWarnings),
        MAP_FUNCTION(bitAnd),
        MAP_FUNCTION(bitOr),
        MAP_FUNCTION(bitLShift),
        MAP_FUNCTION(bitRShift),
		MAP_FUNCTION(sha1_hash),

        END_MAP
    };

    for(unsigned int i = 0; funcMap[i].name != NULL; i++)
        lua_register(lstate, funcMap[i].name, funcMap[i].func);

    // Set up finalizers (destructors) and other metatable stuff
    luaL_newmetatable(lstate, metatable_handle);
    lua_pushstring(lstate, "__gc");
    lua_pushcfunction(lstate, handle_gc);
    lua_settable(lstate, -3);

    luaL_newmetatable(lstate, metatable_hdc);
    lua_pushstring(lstate, "__gc");
    lua_pushcfunction(lstate, hdc_gc);
    lua_settable(lstate, -3);

    luaL_newmetatable(lstate, metatable_netcon);
    lua_pushstring(lstate, "__gc");
    lua_pushcfunction(lstate, netcon_gc);
    lua_settable(lstate, -3);

    luaL_newmetatable(lstate, metatable_audioresource);
    lua_pushstring(lstate, "__gc");
    lua_pushcfunction(lstate, audioresource_gc);
    lua_settable(lstate, -3);

	luaL_newmetatable(lstate, metatable_int64);
	lua_pushstring(lstate, "__add");
	lua_pushcfunction(lstate, int64_add);
	lua_settable(lstate, -3);
	lua_pushstring(lstate, "__sub");
	lua_pushcfunction(lstate, int64_subtract);
	lua_settable(lstate, -3);
	lua_pushstring(lstate, "__mul");
	lua_pushcfunction(lstate, int64_multiply);
	lua_settable(lstate, -3);
	lua_pushstring(lstate, "__div");
	lua_pushcfunction(lstate, int64_divide);
	lua_settable(lstate, -3);
	lua_pushstring(lstate, "__eq");
	lua_pushcfunction(lstate, int64_eq);
	lua_settable(lstate, -3);
	lua_pushstring(lstate, "__lt");
	lua_pushcfunction(lstate, int64_lt);
	lua_settable(lstate, -3);
	lua_pushstring(lstate, "__gt");
	lua_pushcfunction(lstate, int64_gt);
	lua_settable(lstate, -3);
}

// Finalizers (destructors)
int handle_gc(lua_State *lstate)
{
    HANDLE *handle = (HANDLE *)lua_touserdata(lstate, 1);
    Macro::instance()->closeProcess(*handle);

    return 0;
}

int hdc_gc(lua_State *lstate)
{
    WinDC *windc = (WinDC *)lua_touserdata(lstate, 1);

    Macro::instance()->closeDC(*windc);

    return 0;
}

int netcon_gc(lua_State *lstate)
{
    NetCon *lnetcon;
    lnetcon = (NetCon *)lua_touserdata(lstate, 1);

    Macro::instance()->netCloseCon(*lnetcon);

    return 0;
}

int audioresource_gc(lua_State *lstate)
{
	AudioResource *laudioresource;
	laudioresource = (AudioResource *)lua_touserdata(lstate, 1);

	delete laudioresource;
	return 0;
}

int int64_add(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
	//if( !(lua_istable(lstate, 1) || lua_isnumber(lstate, 1)) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_TABLE | T_NUMBER, 1);
	//if( !(lua_istable(lstate, 2) || lua_isnumber(lstate, 2)) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_TABLE | T_NUMBER, 2);

    LARGE_INTEGER t3, t2, t1; // t3 = return value, t1/t2 = inputs

    // Get info from arg 1
    if( lua_isnumber(lstate, 1) )
	{
        t2.HighPart = 0; t2.LowPart = (unsigned int)lua_tonumber(lstate, 1);
	}
    else
		t2 = lua_toint64(lstate, 1);

    // Get info from arg 2
    if( lua_isnumber(lstate, 2) )
	{
        t1.HighPart = 0; t1.LowPart = (unsigned int)lua_tonumber(lstate, 2);
	}
    else
		t1 = lua_toint64(lstate, 2);


	t3.QuadPart = t2.QuadPart + t1.QuadPart;

	lua_newtable(lstate);
    luaL_getmetatable(lstate, metatable_int64);
    lua_setmetatable(lstate, -2);

    lua_pushstring(lstate, "high"); //key
    lua_pushnumber(lstate, t3.HighPart); //value
    lua_settable(lstate, -3);

    lua_pushstring(lstate, "low"); //key
    lua_pushnumber(lstate, t3.LowPart); //value
    lua_settable(lstate, -3);

	return 1;
}

int int64_subtract(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
	//if( !(lua_istable(lstate, 1) || lua_isnumber(lstate, 1)) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_TABLE | T_NUMBER, 1);
	//if( !(lua_istable(lstate, 2) || lua_isnumber(lstate, 2)) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_TABLE | T_NUMBER, 2);

    LARGE_INTEGER t3, t2, t1; // t3 = return value, t1/t2 = inputs

    // Get info from arg 1
    if( lua_isnumber(lstate, 1) )
	{
        t2.HighPart = 0; t2.LowPart = (unsigned int)lua_tonumber(lstate, 1);
	}
    else
		t2 = lua_toint64(lstate, 1);

    // Get info from arg 2
    if( lua_isnumber(lstate, 2) )
	{
        t1.HighPart = 0; t1.LowPart = (unsigned int)lua_tonumber(lstate, 2);
	}
    else
		t1 = lua_toint64(lstate, 2);


	t3.QuadPart = t2.QuadPart - t1.QuadPart;

	lua_newtable(lstate);
    luaL_getmetatable(lstate, metatable_int64);
    lua_setmetatable(lstate, -2);

    lua_pushstring(lstate, "high"); //key
    lua_pushnumber(lstate, t3.HighPart); //value
    lua_settable(lstate, -3);

    lua_pushstring(lstate, "low"); //key
    lua_pushnumber(lstate, t3.LowPart); //value
    lua_settable(lstate, -3);

	return 1;
}

int int64_multiply(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
	//if( !(lua_istable(lstate, 1) || lua_isnumber(lstate, 1)) )
    //    invalidData(lstate, 1);
	//if( !(lua_istable(lstate, 2) || lua_isnumber(lstate, 2)) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_TABLE | T_NUMBER, 1);
	checkType(lstate, T_TABLE | T_NUMBER, 2);

    LARGE_INTEGER t3, t2, t1; // t3 = return value, t1/t2 = inputs

    // Get info from arg 1
    if( lua_isnumber(lstate, 1) )
	{
        t2.HighPart = 0; t2.LowPart = (unsigned int)lua_tonumber(lstate, 1);
	}
    else
		t2 = lua_toint64(lstate, 1);

    // Get info from arg 2
    if( lua_isnumber(lstate, 2) )
	{
        t1.HighPart = 0; t1.LowPart = (unsigned int)lua_tonumber(lstate, 2);
	}
    else
		t1 = lua_toint64(lstate, 2);


	t3.QuadPart = t2.QuadPart * t1.QuadPart;

	lua_newtable(lstate);
    luaL_getmetatable(lstate, metatable_int64);
    lua_setmetatable(lstate, -2);

    lua_pushstring(lstate, "high"); //key
    lua_pushnumber(lstate, t3.HighPart); //value
    lua_settable(lstate, -3);

    lua_pushstring(lstate, "low"); //key
    lua_pushnumber(lstate, t3.LowPart); //value
    lua_settable(lstate, -3);

	return 1;
}

int int64_divide(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
	//if( !(lua_istable(lstate, 1) || lua_isnumber(lstate, 1)) )
    //    invalidData(lstate, 1);
	//if( !(lua_istable(lstate, 2) || lua_isnumber(lstate, 2)) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_TABLE | T_NUMBER, 1);
	checkType(lstate, T_TABLE | T_NUMBER, 2);

    LARGE_INTEGER t3, t2, t1; // t3 = return value, t1/t2 = inputs

    // Get info from arg 1
    if( lua_isnumber(lstate, 1) )
	{
        t2.HighPart = 0; t2.LowPart = (unsigned int)lua_tonumber(lstate, 1);
	}
    else
		t2 = lua_toint64(lstate, 1);

    // Get info from arg 2
    if( lua_isnumber(lstate, 2) )
	{
        t1.HighPart = 0; t1.LowPart = (unsigned int)lua_tonumber(lstate, 2);
	}
    else
		t1 = lua_toint64(lstate, 2);


	t3.QuadPart = t2.QuadPart / t1.QuadPart;

	lua_newtable(lstate);
    luaL_getmetatable(lstate, metatable_int64);
    lua_setmetatable(lstate, -2);

    lua_pushstring(lstate, "high"); //key
    lua_pushnumber(lstate, t3.HighPart); //value
    lua_settable(lstate, -3);

    lua_pushstring(lstate, "low"); //key
    lua_pushnumber(lstate, t3.LowPart); //value
    lua_settable(lstate, -3);

	return 1;
}

int int64_eq(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
	//if( !(lua_istable(lstate, 1) || lua_isnumber(lstate, 1)) )
    //    invalidData(lstate, 1);
	//if( !(lua_istable(lstate, 2) || lua_isnumber(lstate, 2)) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_TABLE | T_NUMBER, 1);
	checkType(lstate, T_TABLE | T_NUMBER, 2);

    unsigned long high2, low2, high1, low1;
    LARGE_INTEGER t2, t1;

    // Get info from arg 2
    if( lua_isnumber(lstate, 2) )
    {
        high1 = 0; low1 = (int)lua_tonumber(lstate, 2);
    }
    else
    { // Must be a table
        lua_pushstring(lstate, "high");
        lua_gettable(lstate, -2);
        high1 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);

        lua_pushstring(lstate, "low");
        lua_gettable(lstate, -2);
        low1 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);
    }

    // Switch tables now
    lua_pop(lstate, 1);

    // Get info from arg 1
    if( lua_isnumber(lstate, 1) )
    {
        high2 = 0; low2 = (int)lua_tonumber(lstate, 1);
    }
    else
    {
        lua_pushstring(lstate, "high");
        lua_gettable(lstate, -2);
        high2 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);

        lua_pushstring(lstate, "low");
        lua_gettable(lstate, -2);
        low2 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);
    }

    t2.HighPart = high2; t2.LowPart = low2;
    t1.HighPart = high1; t1.LowPart = low1;

	if( t1.QuadPart == t2.QuadPart )
		lua_pushboolean(lstate, true);
	else
		lua_pushboolean(lstate, false);

	return 1;
}

int int64_lt(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
	//if( !(lua_istable(lstate, 1) || lua_isnumber(lstate, 1)) )
    //    invalidData(lstate, 1);
	//if( !(lua_istable(lstate, 2) || lua_isnumber(lstate, 2)) )
	//		invalidData(lstate, 2);
	checkType(lstate, T_TABLE | T_NUMBER, 1);
	checkType(lstate, T_TABLE | T_NUMBER, 2);

    unsigned long high2, low2, high1, low1;
    LARGE_INTEGER t2, t1;

    // Get info from arg 2
    if( lua_isnumber(lstate, 2) )
    {
        high1 = 0; low1 = (int)lua_tonumber(lstate, 2);
    }
    else
    { // Must be a table
        lua_pushstring(lstate, "high");
        lua_gettable(lstate, -2);
        high1 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);

        lua_pushstring(lstate, "low");
        lua_gettable(lstate, -2);
        low1 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);
    }

    // Switch tables now
    lua_pop(lstate, 1);

    // Get info from arg 1
    if( lua_isnumber(lstate, 1) )
    {
        high2 = 0; low2 = (int)lua_tonumber(lstate, 1);
    }
    else
    {
        lua_pushstring(lstate, "high");
        lua_gettable(lstate, -2);
        high2 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);

        lua_pushstring(lstate, "low");
        lua_gettable(lstate, -2);
        low2 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);
    }

    t2.HighPart = high2; t2.LowPart = low2;
    t1.HighPart = high1; t1.LowPart = low1;

	if( t2.QuadPart < t1.QuadPart )
		lua_pushboolean(lstate, true);
	else
		lua_pushboolean(lstate, false);

	return 1;
}

int int64_gt(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
	//if( !(lua_istable(lstate, 1) || lua_isnumber(lstate, 1)) )
    //    invalidData(lstate, 1);
	//if( !(lua_istable(lstate, 2) || lua_isnumber(lstate, 2)) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_TABLE | T_NUMBER, 1);
	checkType(lstate, T_TABLE | T_NUMBER, 2);

    unsigned long high2, low2, high1, low1;
    LARGE_INTEGER t2, t1;

    // Get info from arg 2
    if( lua_isnumber(lstate, 2) )
    {
        high1 = 0; low1 = (int)lua_tonumber(lstate, 2);
    }
    else
    { // Must be a table
        lua_pushstring(lstate, "high");
        lua_gettable(lstate, -2);
        high1 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);

        lua_pushstring(lstate, "low");
        lua_gettable(lstate, -2);
        low1 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);
    }

    // Switch tables now
    lua_pop(lstate, 1);

    // Get info from arg 1
    if( lua_isnumber(lstate, 1) )
    {
        high2 = 0; low2 = (int)lua_tonumber(lstate, 1);
    }
    else
    {
        lua_pushstring(lstate, "high");
        lua_gettable(lstate, -2);
        high2 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);

        lua_pushstring(lstate, "low");
        lua_gettable(lstate, -2);
        low2 = (unsigned long)lua_tonumber(lstate, -1);
        lua_pop(lstate, 1);
    }

    t2.HighPart = high2; t2.LowPart = low2;
    t1.HighPart = high1; t1.LowPart = low1;

	if( t2.QuadPart > t1.QuadPart )
		lua_pushboolean(lstate, true);
	else
		lua_pushboolean(lstate, false);

	return 1;
}


int mouseSetDelay(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
        //invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    unsigned int delay = (unsigned int)lua_tonumber(lstate, 1);
    Macro::instance()->mouseSetDelay(delay);

    return 0;
}

int mouseMove(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    int _dx;
    int _dy;

    _dx = (int)lua_tonumber(lstate, 1);
    _dy = (int)lua_tonumber(lstate, 2);

    Macro::instance()->mouseMove(_dx, _dy);

    return 0;
}

int mouseSet(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    int _dx, _dy;
    _dx = (int)lua_tonumber(lstate, 1);
    _dy = (int)lua_tonumber(lstate, 2);

    Macro::instance()->mouseSet(_dx, _dy);

    return 0;
}

int mouseLHold(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    Macro::instance()->mouseLHold();

    return 0;
}

int mouseLRelease(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    Macro::instance()->mouseLRelease();

    return 0;
}

int mouseLClick(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 0 || lua_gettop(lstate) == 1) )
        wrongArgs(lstate);

    int modifier = 0;
    if( lua_gettop(lstate) >= 1 )
        modifier = (int)lua_tonumber(lstate, 1);

    Macro::instance()->mouseLClick(modifier);

    return 0;
}

int mouseMHold(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    Macro::instance()->mouseMHold();

    return 0;
}

int mouseMRelease(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    Macro::instance()->mouseLRelease();

    return 0;
}

int mouseMClick(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 0 || lua_gettop(lstate) == 1) )
        wrongArgs(lstate);

    int modifier = 0;
    if( lua_gettop(lstate) >= 1 )
        modifier = (int)lua_tonumber(lstate, 1);

    Macro::instance()->mouseMClick(modifier);

    return 0;
}

int mouseRHold(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    Macro::instance()->mouseRHold();

    return 0;
}

int mouseRRelease(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    Macro::instance()->mouseRRelease();

    return 0;
}

int mouseRClick(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 0 || lua_gettop(lstate) == 1) )
        wrongArgs(lstate);

    int modifier = 0;
    if( lua_gettop(lstate) >= 1 )
        modifier = (int)lua_tonumber(lstate, 1);

    Macro::instance()->mouseRClick(modifier);

    return 0;
}

int mouseWheelMove(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int moveAmount = (int)lua_tonumber(lstate, 1);

    Macro::instance()->mouseWheelMove(moveAmount);

    return 0;
}

int mouseGetPos(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    long x, y;
    x = Macro::instance()->mouseGetX();
    y = Macro::instance()->mouseGetY();

    lua_pushnumber(lstate, x);
    lua_pushnumber(lstate, y);

    return 2;
}


int keyboardSetDelay(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    long newDelay;
    newDelay = (long)lua_tonumber(lstate, 1);
    Macro::instance()->keyboardSetDelay(newDelay);

    return 0;
}

int keyboardHold(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int key;
    key = (int)lua_tonumber(lstate, 1);
    Macro::instance()->keyboardHold(key);

    return 0;
}

int keyboardRelease(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int key;
    key = (int)lua_tonumber(lstate, 1);
    Macro::instance()->keyboardRelease(key);

    return 0;
}

int keyboardPress(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 1 || lua_gettop(lstate) == 2) )
        wrongArgs(lstate);
	//if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int key; int modifier = 0;
    key = (int)lua_tonumber(lstate, 1);
    if( lua_gettop(lstate) >= 2 )
        modifier = (int)lua_tonumber(lstate, 2);

    Macro::instance()->keyboardPress(key, modifier);

    return 0;
}

int keyboardState(lua_State *lstate)
{
	if( lua_gettop(lstate) != 0 )
		wrongArgs(lstate);
	BYTE ks[256] = {0};
	Macro::instance()->keyboardState(ks);

	lua_newtable(lstate);
	for(unsigned int i = 0; i < 256; i++)
	{
		lua_pushnumber(lstate, i); // key
		lua_pushboolean(lstate, ks[i] != 0); // value
		lua_settable(lstate, -3);
	}

	return 1;
}

int keyPressed(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int key;
    key = (int)lua_tonumber(lstate, 1);
    lua_pushboolean(lstate, Macro::instance()->keyPressed(key));

    return 1;
}

int keyPressedLocal(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int key;
    key = (int)lua_tonumber(lstate, 1);
    lua_pushboolean(lstate, Macro::instance()->keyPressedLocal(key));

    return 1;
}

int keyboardType(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    const char *msg;
    msg = (const char *)lua_tostring(lstate, 1);
    Macro::instance()->keyboardType(msg);

    return 1;
}

int keyboardBufferClear(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    Macro::instance()->keyboardBufferClear();

    return 0;
}

int getKeyName(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    unsigned int key = (unsigned int)lua_tonumber(lstate, 1);
    std::string keyname;
    keyname = Macro::instance()->getKeyName(key);

    lua_pushstring(lstate, keyname.c_str());
    return 1;
}



int attach(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
	//	invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    HWND hwnd;
    hwnd = (HWND)int(lua_tonumber(lstate, 1));
    Macro::instance()->attach(hwnd);

    return 0;
}

int attachKeyboard(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
		wrongArgs(lstate);
	//if( !lua_isnumber(lstate, 1) )
	//	invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

	HWND hwnd;
	hwnd = (HWND)int(lua_tonumber(lstate, 1));
	Macro::instance()->attachKeyboard(hwnd);

	return 0;
}

int attachMouse(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
		wrongArgs(lstate);
	//if( !lua_isnumber(lstate, 1) )
	//	invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

	HWND hwnd;
	hwnd = (HWND)int(lua_tonumber(lstate, 1));
	Macro::instance()->attachMouse(hwnd);

	return 0;
}

int detach(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    Macro::instance()->detach();
    return 0;
}

int getAttachedHwnd(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    int iHwnd = (int)(Macro::instance()->getAttachedHwnd());
    lua_pushnumber(lstate, iHwnd);
    return 1;
}

int openProcess(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int proc;
    proc = (int)lua_tonumber(lstate, 1);

    HANDLE *handle = (HANDLE *)lua_newuserdata(lstate, sizeof(HANDLE));
    // set metatable
    luaL_getmetatable(lstate, metatable_handle);
    lua_setmetatable(lstate, -2);

    *handle = Macro::instance()->openProcess(proc);

    return 1;
}

int closeProcess(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    Macro::instance()->closeProcess(*handle);

    return 0;
}

int findProcess(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    int err;
    const char *name = lua_tostring(lstate, 1);
    DWORD proc = Macro::instance()->findProcess(name, err);

    lua_pushnumber(lstate, (unsigned long)proc);
    return 1;
}

int findProcessByExe(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
	//	invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    int err;
    const char *name = lua_tostring(lstate, 1);
    DWORD proc = Macro::instance()->findProcessByExe(name, err);

    lua_pushnumber(lstate, (unsigned long)proc);
    return 1;
}

int findProcessByWindow(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int err;
    HWND hwnd = (HWND)int(lua_tonumber(lstate, 1));
    DWORD proc = Macro::instance()->findProcessByWindow(hwnd, err);

    lua_pushnumber(lstate, (unsigned long)proc);
    return 1;
}

int getWindowParent(lua_State *lstate)
{
	if( !lua_gettop(lstate) == 1 )
		wrongArgs(lstate);
	checkType(lstate, T_NUMBER, 1);

	HWND child = (HWND)(int)lua_tonumber(lstate, 1);
	HWND parent = Macro::instance()->getWindowParent(child);

	if( parent )
		lua_pushnumber(lstate, (int)parent);
	else
		lua_pushnil(lstate);

	return 1;
}

int findWindow(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 1 || lua_gettop(lstate) == 2) )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);
    if( lua_gettop(lstate) == 2 )
    {
        //if( !lua_isstring(lstate, 2) )
        //    invalidData(lstate, 2);
		checkType(lstate, T_STRING, 2);
    }

    int err;
    const char *name = lua_tostring(lstate, 1);
    std::string classname = "";

    if( lua_gettop(lstate) >= 2 )
        classname = (char *)lua_tostring(lstate, 2);

    int retval = (int)Macro::instance()->findWindow(name, classname, err);

    lua_pushnumber(lstate, retval);
    return 1;
}

int findWindowList(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 1 || lua_gettop(lstate) == 2) )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);
    if( lua_gettop(lstate) == 2 )
    {
        //if( !lua_isstring(lstate, 2) )
        //    invalidData(lstate, 2);
		checkType(lstate, T_STRING, 2);
    }

    std::string classname;
    if( lua_gettop(lstate) >= 2 )
        classname = (std::string)lua_tostring(lstate, 2);

    int err;
    const char *name = lua_tostring(lstate, 1);
    std::vector<HWND> retlist;
    Macro::instance()->findWindowList(name, classname, retlist, err);

    lua_newtable(lstate);
    for(unsigned int i = 0; i < retlist.size(); i++)
    {
        lua_pushnumber(lstate, i+1); //key
        lua_pushnumber(lstate, (int)retlist[i]); //value
        lua_settable(lstate, -3);
    }

    return 1;
}

int foregroundWindow(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    lua_pushnumber(lstate, (int)Macro::instance()->foregroundWindow());
    return 1;
}

int getHwnd(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    HWND hwnd = Macro::instance()->getHwnd();

    lua_pushnumber(lstate, (int)hwnd);
    return 1;
}

int getWindowName(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int err;
    HWND hwnd = (HWND)int(lua_tonumber(lstate, 1));
    lua_pushstring(lstate, Macro::instance()->getWindowName(hwnd, err).c_str());

    return 1;
}

int getWindowClassName(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int err;
    HWND hwnd = (HWND)int(lua_tonumber(lstate, 1));
    lua_pushstring(lstate,
		Macro::instance()->getWindowClassName(hwnd, err).c_str());

    return 1;
}

int setWindowName(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);
    //if( !lua_isstring(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_STRING, 2);

    HWND hwnd = (HWND)int(lua_tonumber(lstate, 1));
    std::string name = (std::string)lua_tostring(lstate, 2);
    int err;

    Macro::instance()->setWindowName(hwnd, name, err);

    return 0;
}

int windowValid(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    HWND hwnd = (HWND)int(lua_tonumber(lstate, 1));

    lua_pushboolean(lstate, Macro::instance()->windowValid(hwnd));
    return 1;
}

int windowRect(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int x,y,w,h;
    HWND hwnd = (HWND)int(lua_tonumber(lstate, 1));
    RECT rect = Macro::instance()->windowRect(hwnd);
    x = rect.left; y = rect.top;
    w = rect.right;
    h = rect.bottom;

    lua_pushnumber(lstate, x);
    lua_pushnumber(lstate, y);
    lua_pushnumber(lstate, w);
    lua_pushnumber(lstate, h);

    return 4;
}

int openDC(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    HWND hwnd = (HWND)int(lua_tonumber(lstate, 1) );
    if( hwnd == 0 )
        invalidData(lstate, 1);

    WinDC *windc = (WinDC *)lua_newuserdata(lstate, sizeof(WinDC));
    // Set metatable
    luaL_getmetatable(lstate, metatable_hdc);
    lua_setmetatable(lstate, -2);

    WinDC recvdc = Macro::instance()->openDC(hwnd);
    memcpy((void*)(windc), (void*)&recvdc, sizeof(WinDC));
    //*windc = Macro::instance()->openDC(hwnd);

    return 1;
}

int closeDC(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);

    WinDC *windc = (WinDC *)lua_touserdata(lstate, 1);
    if( windc->hDc == 0 )
        invalidData(lstate, 1);

    Macro::instance()->closeDC(*windc);
    return 0;
}

int makeColor(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isnumber(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_NUMBER, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);

    int r, g, b;
    r = (int)lua_tonumber(lstate, 1);
    g = (int)lua_tonumber(lstate, 2);
    b = (int)lua_tonumber(lstate, 3);

    int col = Macro::instance()->makeColor(r, g, b);
    lua_pushnumber(lstate, col);

    return 1;
}

int getR(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1)
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int col = (int)lua_tonumber(lstate, 1);
    lua_pushnumber(lstate, Macro::instance()->getR(col));

    return 1;
}

int getG(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int col = (int)lua_tonumber(lstate, 1);
    lua_pushnumber(lstate, Macro::instance()->getG(col));

    return 1;
}

int getB(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int col = (int)lua_tonumber(lstate, 1);
    lua_pushnumber(lstate, Macro::instance()->getB(col));

    return 1;
}

int getPixel(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);

    WinDC *windc = (WinDC *)lua_touserdata(lstate, 1);
    if( windc->hWnd == 0 )
        invalidData(lstate, 1);

    int px = (int)lua_tonumber(lstate, 2);
    int py = (int)lua_tonumber(lstate, 3);

    int col = Macro::instance()->getPixel(windc, px, py);
    int r, g, b;
    r = Macro::instance()->getR(col);
    g = Macro::instance()->getG(col);
    b = Macro::instance()->getB(col);

    lua_pushnumber(lstate, r);
    lua_pushnumber(lstate, g);
    lua_pushnumber(lstate, b);

    return 3;
}

int setPixel(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);
    if( !lua_isnumber(lstate, 4) )
        invalidData(lstate, 4);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);
	checkType(lstate, T_NUMBER, 4);

    WinDC *windc = (WinDC *)lua_touserdata(lstate, 1);
    if( windc->hWnd == 0 )
        invalidData(lstate, 1);

    int px = (int)lua_tonumber(lstate, 2);
    int py = (int)lua_tonumber(lstate, 3);
    int col = (int)lua_tonumber(lstate, 4);

    Macro::instance()->setPixel(windc, px, py, col);

    return 0;
}

int pixelSearch(lua_State *lstate)
{
    if( !(lua_gettop(lstate) >= 6 && lua_gettop(lstate) <= 8) )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);
    if( !lua_isnumber(lstate, 4) )
        invalidData(lstate, 4);
    if( !lua_isnumber(lstate, 5) )
        invalidData(lstate, 5);
    if( !lua_isnumber(lstate, 6) )
        invalidData(lstate, 6);
    if( lua_gettop(lstate) >= 7 && !lua_isnumber(lstate, 7) )
        invalidData(lstate, 7);
    if( lua_gettop(lstate) >= 8 && !lua_isnumber(lstate, 8) )
        invalidData(lstate, 8);*/

	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);
	checkType(lstate, T_NUMBER, 4);
	checkType(lstate, T_NUMBER, 5);
	checkType(lstate, T_NUMBER, 6);
	if( lua_gettop(lstate) >= 7 )
		checkType(lstate, T_NUMBER, 7);
	if( lua_gettop(lstate) >= 8 )
		checkType(lstate, T_NUMBER, 8);

    WinDC *windc = (WinDC *)lua_touserdata(lstate, 1);

    if( windc->hWnd == 0 )
        invalidData(lstate, 1);

    int color = (int)(lua_tonumber(lstate, 2));
    int x1 = (int)(lua_tonumber(lstate, 3));
    int y1 = (int)(lua_tonumber(lstate, 4));
    int x2 = (int)(lua_tonumber(lstate, 5));
    int y2 = (int)(lua_tonumber(lstate, 6));
    unsigned char accuracy = 0;
    int step = 1;

    if( lua_gettop(lstate) >= 7 )
        accuracy = (int)(lua_tonumber(lstate, 7));
    if( lua_gettop(lstate) >= 8 )
        step = (int)(lua_tonumber(lstate, 8));

    POINT pt = Macro::instance()->pixelSearch(windc, color, x1, y1, x2, y2,
        accuracy, step);

    lua_pushnumber(lstate, pt.x);
    lua_pushnumber(lstate, pt.y);

    return 2;
}

int drawLine(lua_State *lstate)
{
    if( lua_gettop(lstate) != 7 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);
    if( !lua_isnumber(lstate, 4) )
        invalidData(lstate, 4);
    if( !lua_isnumber(lstate, 5) )
        invalidData(lstate, 5);
    if( !lua_isnumber(lstate, 6) )
        invalidData(lstate, 6);
    if( !lua_isnumber(lstate, 7) )
        invalidData(lstate, 7);*/

	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);
	checkType(lstate, T_NUMBER, 4);
	checkType(lstate, T_NUMBER, 5);
	checkType(lstate, T_NUMBER, 6);
	checkType(lstate, T_NUMBER, 7);

  WinDC *windc = (WinDC *)lua_touserdata(lstate, 1);
  if( windc->hDc == 0 )
    invalidData(lstate, 1);

  int x1 = (int)(lua_tonumber(lstate, 2));
  int y1 = (int)(lua_tonumber(lstate, 3));
  int x2 = (int)(lua_tonumber(lstate, 4));
  int y2 = (int)(lua_tonumber(lstate, 5));
  int col = (int)(lua_tonumber(lstate, 6));
  int size = (int)(lua_tonumber(lstate, 7));

  Macro::instance()->drawLine(windc->hDc, x1, y1, x2, y2, col, size);

  return 0;
}

int drawRect(lua_State *lstate)
{
    if( lua_gettop(lstate) != 7 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);
    if( !lua_isnumber(lstate, 4) )
        invalidData(lstate, 4);
    if( !lua_isnumber(lstate, 5) )
        invalidData(lstate, 5);
    if( !lua_isnumber(lstate, 6) )
        invalidData(lstate, 6);
    if( !lua_isnumber(lstate, 7) )
        invalidData(lstate, 7);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);
	checkType(lstate, T_NUMBER, 4);
	checkType(lstate, T_NUMBER, 5);
	checkType(lstate, T_NUMBER, 6);
	checkType(lstate, T_NUMBER, 7);

    WinDC *windc = (WinDC *)lua_touserdata(lstate, 1);
    if( windc->hDc == 0 )
        invalidData(lstate, 1);

    int x1 = (int)(lua_tonumber(lstate, 2));
    int y1 = (int)(lua_tonumber(lstate, 3));
    int x2 = (int)(lua_tonumber(lstate, 4));
    int y2 = (int)(lua_tonumber(lstate, 5));
    int col = (int)(lua_tonumber(lstate, 6));
    int size = (int)(lua_tonumber(lstate, 7));

    Macro::instance()->drawRect(windc->hDc, x1, y1, x2, y2, col, size);

    return 0;
}

int saveScreenshot(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);
    //if( !lua_isstring(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_STRING, 2);

    HWND hwnd = (HWND)int(lua_tonumber(lstate, 1));
    const char *fn = lua_tostring(lstate, 2);

    Macro::instance()->saveScreenshot(hwnd, fn);
    return 0;
}

int getClipboard(lua_State *lstate)
{
	if( lua_gettop(lstate) != 0 )
		wrongArgs(lstate);

	std::string str = Macro::instance()->getClipboard();

	lua_pushstring(lstate, (char *)str.c_str());
	return 1;
}

int setClipboard(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1)
		wrongArgs(lstate);
	//if( !lua_isstring(lstate, 1) )
	//	invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

	char *str = (char *)lua_tostring(lstate, 1);

	Macro::instance()->setClipboard(str);
	return 0;
}

int showWindow(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    HWND hwnd = (HWND)int(lua_tonumber(lstate, 1));
    int cmd = (int)lua_tonumber(lstate, 2);

    Macro::instance()->showWindow(hwnd, cmd);

    return 0;
}

int setWindowPos(lua_State *lstate)
{
	int argc = lua_gettop(lstate);
	// Accept 5 or 6 args
	if( argc != 5 && argc != 6 )
		wrongArgs(lstate);

	checkType(lstate, T_NUMBER, 1);
	checkType(lstate, T_NUMBER | T_NIL, 2);
	checkType(lstate, T_NUMBER | T_NIL, 3);
	checkType(lstate, T_NUMBER | T_NIL, 4);
	checkType(lstate, T_NUMBER | T_NIL, 5);
	if( argc > 5 )
		checkType(lstate, T_BOOLEAN | T_NUMBER | T_NIL, 6);

	HWND hwnd = (HWND)int(lua_tonumber(lstate, 1));
	RECT winrect;
	GetWindowRect(hwnd, &winrect);
	HWND insAfter = 0;
	unsigned int flags = SWP_SHOWWINDOW;

	int x = winrect.left, y = winrect.top, w = winrect.right, h = winrect.bottom;

	if( lua_isnumber(lstate, 2) )
		winrect.left = (int)lua_tonumber(lstate, 2);
	if( lua_isnumber(lstate, 3) )
		winrect.top = (int)lua_tonumber(lstate, 3);
	if( lua_isnumber(lstate, 4) )
		winrect.right = winrect.left + (int)lua_tonumber(lstate, 4);
	else
		winrect.right = winrect.left + (w-x);
	if( lua_isnumber(lstate, 5) )
		winrect.bottom = winrect.top + (int)lua_tonumber(lstate, 5);
	else
		winrect.bottom = winrect.top + (h-y);

	if( argc > 5 && !lua_isnil(lstate, 6) )
	{
		if( (int)lua_toboolean(lstate, 6) )
			insAfter = HWND_TOPMOST;
		else
			insAfter = HWND_NOTOPMOST;
	}

	SetWindowPos(hwnd, insAfter, winrect.left, winrect.top, winrect.right - winrect.left,
		winrect.bottom - winrect.top, flags);

	return 0;
}

int findPatternInProcess(lua_State *lstate)
{
    if( lua_gettop(lstate) < 3 || lua_gettop(lstate) > 5 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isstring(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isstring(lstate, 3) )
        invalidData(lstate, 3);

    if( lua_gettop(lstate) >= 4 )
        if( !lua_isnumber(lstate, 4) )
            invalidData(lstate, 4);
    if( lua_gettop(lstate) >= 5 )
        if( !lua_isnumber(lstate, 5) )
            invalidData(lstate, 5);*/

	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_STRING, 2);
	checkType(lstate, T_STRING, 3);
    if( lua_gettop(lstate) >= 4 )
		checkType(lstate, T_NUMBER, 4);
    if( lua_gettop(lstate) >= 5 )
		checkType(lstate, T_NUMBER, 5);


    HANDLE *handle;
    unsigned char *bmask;
    char *szMask;
    unsigned long address = 0;
    unsigned long len = 100000;

    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    bmask = (unsigned char *)lua_tostring(lstate, 2);
    szMask = (char *)lua_tostring(lstate, 3);

    if( lua_gettop(lstate) >= 4 )
        address = (unsigned long)lua_tonumber(lstate, 4);

    if( lua_gettop(lstate) >= 5 )
        len = (unsigned long)lua_tonumber(lstate, 5);

    unsigned long foundAddr = Macro::instance()->findPatternInProcess(*handle,
        bmask, szMask, address, len);

    lua_pushnumber(lstate, foundAddr);
    return 1;
}

int getModuleAddress(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
		wrongArgs(lstate);
	//if( !lua_isnumber(lstate, 1) )
	//	invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);
	//if( !lua_isstring(lstate, 2) )
	//	invalidData(lstate, 2);
	checkType(lstate, T_STRING, 1);

	DWORD procId;
	std::string modname;

	procId = (DWORD)lua_tonumber(lstate, 1);
	modname = (std::string)lua_tostring(lstate, 2);

	lua_pushnumber(lstate,
		Macro::instance()->getModuleAddress(procId, modname.c_str()));

	return 1;
}

int flashWindow(lua_State *lstate)
{
	if( lua_gettop(lstate) > 2 )
		wrongArgs(lstate);

	HWND hwnd = NULL;
	int count = 0;

	if( lua_gettop(lstate) >= 1 )
	{
		checkType(lstate, T_NUMBER | T_NIL, 1);
		if( lua_isnil(lstate, 1) )
			hwnd = NULL;
		else
			hwnd = (HWND)(int)lua_tonumber(lstate, 1);
	}

	if( lua_gettop(lstate) >= 2 )
	{
		checkType(lstate, T_NUMBER | T_NIL, 2);
		if( lua_isnil(lstate, 2) )
			count = 0;
		else
			count = (int)lua_tonumber(lstate, 2);
	}

	Macro::instance()->flashWindow(hwnd, count);
	return 0;
}

int getConsoleAttributes(lua_State *lstate)
{
	if( lua_gettop(lstate) != 0 )
		wrongArgs(lstate);

	CONSOLE_SCREEN_BUFFER_INFO lpcsbi;
	if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &lpcsbi) )
	{
		lua_pushnumber(lstate, lpcsbi.srWindow.Right + 1);
		lua_pushnumber(lstate, lpcsbi.srWindow.Bottom - lpcsbi.srWindow.Top + 1);
		lua_pushnumber(lstate, lpcsbi.dwSize.X);
		lua_pushnumber(lstate, lpcsbi.dwSize.Y);
		lua_pushnumber(lstate, lpcsbi.dwCursorPosition.X + 1);
		lua_pushnumber(lstate, lpcsbi.dwCursorPosition.Y + 1);
		return 6;
	}
	else
	{
		return 0; // Error
	}
}

int setConsoleAttributes(lua_State *lstate)
{
	int args = lua_gettop(lstate);
	if( args != 2 && args != 4 )
		wrongArgs(lstate);

	checkType(lstate, T_NUMBER, 1);
	checkType(lstate, T_NUMBER, 2);

	if( args >= 4 )
	{
		checkType(lstate, T_NUMBER, 3);
		checkType(lstate, T_NUMBER, 4);
	}

	SMALL_RECT rect;

	//rect.Left = (int)lua_tonumber(lstate, 3);
	//rect.Top = (int)lua_tonumber(lstate, 4);
	rect.Right = (int)lua_tonumber(lstate, 1) - 1;
	rect.Bottom = (int)lua_tonumber(lstate, 2) - 1;
	rect.Left = 0;
	rect.Top = 0;

	SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), true, &rect);

	if( args >= 4 )
	{
		COORD coord;
		coord.X = (int)lua_tonumber(lstate, 3);
		coord.Y = (int)lua_tonumber(lstate, 4);
		SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coord);
	}

	return 0;
}

int getPath(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    lua_pushstring(lstate, Macro::instance()->getPath().c_str());

    return 1;
}

int getExecutionPath(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    lua_pushstring(lstate, Macro::instance()->getExecutionPath().c_str());

    return 1;
}

int setExecutionPath(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    std::string path = lua_tostring(lstate, 1);
    Macro::instance()->setExecutionPath(path);

    return 0;
}

int getFileName(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    const char *filename = lua_tostring(lstate, 1);
    lua_pushstring(lstate, Macro::instance()->getFileName(filename).c_str());

    return 1;
}

int getFilePath(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    const char *filepath = lua_tostring(lstate, 1);
    lua_pushstring(lstate, Macro::instance()->getFilePath(filepath).c_str());

    return 1;
}

int getDirectory(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    std::string path = lua_tostring(lstate, 1);
    std::vector<std::string> files;

    Macro::instance()->getDirectory(path, files, "");
    if( files.size() == 0 )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_newtable(lstate);
    for(unsigned int i = 0; i < files.size(); i++)
    {
        lua_pushnumber(lstate, i+1); // Key
        lua_pushstring(lstate, files.at(i).c_str());
        lua_settable(lstate, -3);
    }

    return 1;
}

int isDirectory(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

	std::string path = (std::string)lua_tostring(lstate, 1);
	lua_pushboolean(lstate, Macro::instance()->isDirectory(path));

	return 1;
}



int memoryReadByte(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);
	//if( !lua_isnumber(lstate, 2) )
	//	invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    char value = Macro::instance()->memoryReadByte(*handle, address, err);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadUByte(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    unsigned char value = Macro::instance()->memoryReadUByte(*handle, address,
		err);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadShort(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    short value = Macro::instance()->memoryReadShort(*handle, address, err);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadUShort(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    unsigned short value = Macro::instance()->memoryReadShort(*handle,
		address, err);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}


int memoryReadInt(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    int value = Macro::instance()->memoryReadInt(*handle, address, err);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadUInt(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    unsigned int value = Macro::instance()->memoryReadUInt(*handle, address, err);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadFloat(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    float value = Macro::instance()->memoryReadFloat(*handle, address, err);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadDouble(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    double value = Macro::instance()->memoryReadDouble(*handle, address, err);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}


int memoryReadString(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 2 || lua_gettop(lstate) == 3) )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    long maxlen = 0;
    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    if( lua_gettop(lstate) == 3 )
    { // If they specified a max length
        //if( !lua_isnumber(lstate, 3) )
        //    invalidData(lstate, 3);
		checkType(lstate, T_NUMBER, 3);

        maxlen = (int)lua_tonumber(lstate, 3);
    }

    std::string value = Macro::instance()->memoryReadString(*handle, address,
        err, maxlen);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushstring(lstate, value.c_str());
    return 1;
}

int memoryReadUString(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 2 || lua_gettop(lstate) == 3) )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    int maxlen = 0;
    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    if( lua_gettop(lstate) == 3 )
    { // If they specified a max length
        //if( !lua_isnumber(lstate, 3) )
        //    invalidData(lstate, 3);
		checkType(lstate, T_NUMBER, 3);

        maxlen = (int)lua_tonumber(lstate, 3);
    }

    std::wstring value = Macro::instance()->memoryReadUString(*handle, address,
        err, maxlen);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushstring(lstate, narrowString(value).c_str());
    return 1;
}

int memoryReadBytePtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    //long offset = (int)lua_tonumber(lstate, 3);
    int err = 0;
	char value = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadBytePtr(*handle, address, offset,
        err);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadBytePtr(*handle,
			address, offsets[0], err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				value = Macro::instance()->memoryReadByte(*handle,
				address + offsets[i], err);
		}
	}

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadUBytePtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;
	unsigned char value = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadUBytePtr(*handle,
		address, offset, err);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);


		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadUBytePtr(*handle,
			address, offsets[0], err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				value = Macro::instance()->memoryReadUByte(*handle,
				address + offsets[i], err);
		}
	}

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadShortPtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;
	short value = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadShortPtr(*handle, address,
        offset, err);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadShortPtr(*handle,
			address, offsets[0], err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				value = Macro::instance()->memoryReadShort(*handle,
				address + offsets[i], err);
		}

	}

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadUShortPtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;
	unsigned short value = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadShortPtr(*handle,
		address, offset, err);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadUShortPtr(*handle,
			address, offsets[0], err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				value = Macro::instance()->memoryReadUShort(*handle,
				address + offsets[i], err);
		}
	}

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadIntPtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    //long offset = (int)lua_tonumber(lstate, 3);
    int err = 0;
	int value = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadIntPtr(*handle,
		address, offset, err);
	}
	else
	{ // Read a table
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadIntPtr(*handle,
			address, offsets[0], err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				value = Macro::instance()->memoryReadInt(*handle,
				address + offsets[i], err);
		}
	}


    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadUIntPtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    //long offset = (int)lua_tonumber(lstate, 3);
    int err = 0;
	unsigned int value = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadUIntPtr(*handle,
		address, offset, err);
	}
	else
	{ // Read a table
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				value = Macro::instance()->memoryReadInt(*handle,
				address + offsets[i], err);
		}
	}

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadFloatPtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    //long offset = (int)lua_tonumber(lstate, 3);
    int err = 0;
	float value = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadFloatPtr(*handle, address,
		offset, err);
	}
	else
	{ // Read a table
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadFloatPtr(*handle,
			address, offsets[0], err);
		}
		else
		{
			address = Macro::instance()->memoryReadIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadInt(*handle,
				address + offsets[i], err);
			}
			if( !err )
				value = Macro::instance()->memoryReadFloat(*handle,
				address + offsets[i], err);
		}
	}


    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadDoublePtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    //long offset = (int)lua_tonumber(lstate, 3);
    int err = 0;
	double value = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadDoublePtr(*handle, address,
		offset, err);
	}
	else
	{ // Read a table
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadDoublePtr(*handle,
			address, offsets[0], err);
		}
		else
		{
			address = Macro::instance()->memoryReadIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadInt(*handle,
				address + offsets[i], err);
			}
			if( !err )
				value = Macro::instance()->memoryReadDouble(*handle,
				address + offsets[i], err);
		}
	}


    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushnumber(lstate, value);
    return 1;
}

int memoryReadStringPtr(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 3 ||lua_gettop(lstate) == 4) )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    int maxlen = 0;
    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    //long offset = (int)lua_tonumber(lstate, 3);
    int err = 0;

    if( lua_gettop(lstate) == 4 )
    {
        if( !lua_isnumber(lstate, 4) )
            invalidData(lstate, 4);

        maxlen = (int)lua_tonumber(lstate, 4);
    }

	std::string value;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadStringPtr(*handle, address,
        offset, err, maxlen);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadStringPtr(*handle,
			address, offsets[0], err, maxlen);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				value = Macro::instance()->memoryReadString(*handle,
				address + offsets[i], err, maxlen);
		}
	}

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushstring(lstate, value.c_str());
    return 1;
}

int memoryReadUStringPtr(lua_State *lstate)
{
    if( !(lua_gettop(lstate) == 3 || lua_gettop(lstate) == 4) )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    int maxlen = 0;
    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    int err = 0;

    if( lua_gettop(lstate) == 4 )
    {
        if( !lua_isnumber(lstate, 4) )
            invalidData(lstate, 4);

        maxlen = (int)lua_tonumber(lstate, 4);
    }

	std::wstring value;
	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		value = Macro::instance()->memoryReadUStringPtr(*handle,
		address, offset, err, maxlen);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			value = Macro::instance()->memoryReadUStringPtr(*handle,
			address, offsets[0], err, maxlen);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				value = Macro::instance()->memoryReadUString(*handle,
				address + offsets[i], err, maxlen);
		}
	}

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

    lua_pushstring(lstate, narrowString(value).c_str());
    return 1;
}

int memoryWriteByte(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    unsigned char writedata = (unsigned char)lua_tonumber(lstate, 3);
    int err = 0;

    Macro::instance()->memoryWriteByte(*handle, address, writedata, err);

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteShort(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    unsigned short writedata = (unsigned short)lua_tonumber(lstate, 3);
    int err = 0;

    Macro::instance()->memoryWriteShort(*handle, address, writedata, err);

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteInt(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    unsigned int writedata = (unsigned int)lua_tonumber(lstate, 3);
    int err = 0;

    Macro::instance()->memoryWriteInt(*handle, address, writedata, err);

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteFloat(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    float writedata = (float)lua_tonumber(lstate, 3);
    int err = 0;

    Macro::instance()->memoryWriteFloat(*handle, address, writedata, err);

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteDouble(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !lua_isnumber(lstate, 3) )
        invalidData(lstate, 3);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    double writedata = (double)lua_tonumber(lstate, 3);
    int err = 0;

    Macro::instance()->memoryWriteDouble(*handle, address, writedata, err);

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteString(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_STRING, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

	size_t maxlen = 0;
    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    char *writedata = (char *)lua_tolstring(lstate, 3, &maxlen);
    int err = 0;

    Macro::instance()->memoryWriteString(*handle, address, writedata, err, (unsigned int)maxlen);

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteStringPtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 4 )
        wrongArgs(lstate);
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);
	checkType(lstate, T_STRING, 4);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

	size_t maxlen = 0;
    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    char *writedata = (char *)lua_tolstring(lstate, 3, &maxlen);
    int err = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		Macro::instance()->memoryWriteStringPtr(*handle, address, offset, writedata, err, (unsigned int)maxlen);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			Macro::instance()->memoryWriteStringPtr(*handle,
			address, offsets[0], writedata, err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				Macro::instance()->memoryWriteString(*handle,
				address + offsets[i], writedata, err);
		}

	}

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}



int memoryWriteBytePtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 4 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);
    if( !lua_isnumber(lstate, 4) )
        invalidData(lstate, 4);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);
	checkType(lstate, T_NUMBER, 4);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    //long offset = (int)lua_tonumber(lstate, 3);
    unsigned char writedata = (unsigned char)lua_tonumber(lstate, 4);
    int err = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		Macro::instance()->memoryWriteBytePtr(*handle, address, offset,
		writedata, err);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			Macro::instance()->memoryWriteBytePtr(*handle, address,
			offsets[0], writedata, err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				Macro::instance()->memoryWriteByte(*handle,
				address + offsets[i], writedata, err);
		}
	}

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteShortPtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 4 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);
    if( !lua_isnumber(lstate, 4) )
        invalidData(lstate, 4);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);
	checkType(lstate, T_NUMBER, 4);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    unsigned short writedata = (unsigned short)lua_tonumber(lstate, 4);
    int err = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		Macro::instance()->memoryWriteShortPtr(*handle, address, offset,
		writedata, err);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			Macro::instance()->memoryWriteShortPtr(*handle, address,
			offsets[0], writedata, err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				Macro::instance()->memoryWriteShort(*handle,
				address + offsets[i], writedata, err);
		}

	}

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteIntPtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 4 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);
    if( !lua_isnumber(lstate, 4) )
        invalidData(lstate, 4);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);
	checkType(lstate, T_NUMBER, 4);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    unsigned int writedata = (unsigned int)lua_tonumber(lstate, 4);
    int err = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		Macro::instance()->memoryWriteIntPtr(*handle, address, offset,
		writedata, err);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			Macro::instance()->memoryWriteIntPtr(*handle, address,
			offsets[0], writedata, err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				Macro::instance()->memoryWriteInt(*handle,
				address + offsets[i], writedata, err);
		}

	}

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteFloatPtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 4 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);
    if( !lua_isnumber(lstate, 4) )
        invalidData(lstate, 4);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);
	checkType(lstate, T_NUMBER, 4);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    float writedata = (float)lua_tonumber(lstate, 4);
    int err = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		Macro::instance()->memoryWriteFloatPtr(*handle, address, offset,
		writedata, err);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			Macro::instance()->memoryWriteFloatPtr(*handle, address,
			offsets[0], writedata, err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				Macro::instance()->memoryWriteFloat(*handle,
				address + offsets[i], writedata, err);
		}
	}

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryWriteDoublePtr(lua_State *lstate)
{
    if( lua_gettop(lstate) != 4 )
        wrongArgs(lstate);
    /*if( !lua_isuserdata(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isnumber(lstate, 2) )
        invalidData(lstate, 2);
    if( !(lua_isnumber(lstate, 3) || lua_istable(lstate, 3)) )
        invalidData(lstate, 3);
    if( !lua_isnumber(lstate, 4) )
        invalidData(lstate, 4);*/
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_NUMBER | T_TABLE, 3);
	checkType(lstate, T_NUMBER, 4);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
    double writedata = (double)lua_tonumber(lstate, 4);
    int err = 0;

	if( lua_isnumber(lstate, 3) )
	{
		int offset = (int)lua_tonumber(lstate, 3);
		Macro::instance()->memoryWriteDoublePtr(*handle, address, offset,
		writedata, err);
	}
	else
	{
		std::vector<long> offsets;
		lua_pushnil(lstate);

		while( lua_next(lstate, 3) )
		{
			if( lua_isnumber(lstate, -1) )
			{
				offsets.push_back( (int)lua_tonumber(lstate, -1) );
				lua_pop(lstate, 1);
			}
			else
			{
				// They passed a non-numeric value in the table
				invalidData(lstate, 3);
			}
		}
		lua_pop(lstate, 1); // Pop goes the table.

		if( offsets.size() == 0 )
			invalidData(lstate, 3);

		if( offsets.size() == 1 )
		{
			Macro::instance()->memoryWriteDoublePtr(*handle, address,
			offsets[0], writedata, err);
		}
		else
		{
			address = Macro::instance()->memoryReadUIntPtr(*handle,
			address, offsets[0], err);
			unsigned int i;
			for(i = 1; i < offsets.size() - 1; i++)
			{
				if( err )
					break;
				address = Macro::instance()->memoryReadUInt(*handle,
				address + offsets[i], err);
			}

			if( !err )
				Macro::instance()->memoryWriteDouble(*handle,
				address + offsets[i], writedata, err);
		}
	}

    if( err )
        lua_pushboolean(lstate, false);
    else
        lua_pushboolean(lstate, true);

    return 1;
}

int memoryReadBatch(lua_State *lstate)
{
    if( lua_gettop(lstate) != 3 )
        wrongArgs(lstate);
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);
	checkType(lstate, T_STRING, 3);

    HANDLE *handle;
    handle = (HANDLE *)lua_touserdata(lstate, 1);
    if( *handle == 0 )
        invalidData(lstate, 1);

    unsigned long address = (unsigned int)lua_tonumber(lstate, 2);
	char *fmt = (char *)lua_tostring(lstate, 3);
    int err = 0;
	std::vector<CVardata> vars;

    Macro::instance()->memoryReadBatch(*handle, address, fmt, vars, err);

    if( err )
    {
        lua_pushnil(lstate);
        return 1;
    }

	lua_newtable(lstate);
	for(unsigned int i = 0; i < vars.size(); i++)
	{
		switch(vars.at(i).type)
		{
			case T_BYTE:
				lua_pushnumber(lstate, i + 1);
				lua_pushnumber(lstate, (char)vars.at(i).cData);
				lua_settable(lstate, -3);
			break;
			case T_UBYTE:
				lua_pushnumber(lstate, i + 1);
				lua_pushnumber(lstate, (unsigned char)vars.at(i).cData);
				lua_settable(lstate, -3);
			break;
			case T_SHORT:
				lua_pushnumber(lstate, i + 1);
				lua_pushnumber(lstate, (short)vars.at(i).sData);
				lua_settable(lstate, -3);
			break;
			case T_USHORT:
				lua_pushnumber(lstate, i + 1);
				lua_pushnumber(lstate, (unsigned short)vars.at(i).sData);
				lua_settable(lstate, -3);
			break;
			case T_INT:
				lua_pushnumber(lstate, i + 1);
				lua_pushnumber(lstate, (int)vars.at(i).iData);
				lua_settable(lstate, -3);
			break;
			case T_UINT:
				lua_pushnumber(lstate, i + 1);
				lua_pushnumber(lstate, (unsigned int)vars.at(i).iData);
				lua_settable(lstate, -3);
			break;
			case T_FLOAT:
				lua_pushnumber(lstate, i + 1);
				lua_pushnumber(lstate, (float)vars.at(i).fData);
				lua_settable(lstate, -3);
			break;
			case T_SZSTRING:
				lua_pushnumber(lstate, i + 1);
				lua_pushstring(lstate, (char *)vars.at(i).szData.c_str());
				lua_settable(lstate, -3);
			break;
			case T_UNUSED:
			break; // Avoid warning for unused enumeration value
		}
	}

    return 1;
}

int netPushKey(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    /*if( !lua_isstring(lstate, 1) )
        invalidData(lstate, 1);
    if( !lua_isstring(lstate, 2) )
        invalidData(lstate, 2);*/
	checkType(lstate, T_STRING, 1);
	checkType(lstate, T_STRING, 2);

    std::string keyname = (std::string)lua_tostring(lstate, 1);
    std::string keydata = (std::string)lua_tostring(lstate, 2);

    Macro::instance()->netPushKey(keyname, keydata);

    return 0;
}

int netOpenCon(lua_State *lstate)
{
    // accepts 1 or 2 parameters: binding, encryption key name
    if( !(lua_gettop(lstate) == 1 || lua_gettop(lstate) == 2) )
        wrongArgs(lstate);

    std::string binding;
    std::string keyname;
    int server = false;


    if( lua_gettop(lstate) == 1 )
    { // accept 1 arg: keyname
        //if( !lua_isstring(lstate, 1)  )
        //    invalidData(lstate, 1);
		checkType(lstate, T_STRING, 1);

        keyname = lua_tostring(lstate, 1);
        server = false;
    }
    else
    { // accept 2 args: binding, keyname
        //if( !lua_isstring(lstate, 1) )
        //    invalidData(lstate, 1);
		checkType(lstate, T_STRING, 1);
        //if( !lua_isstring(lstate, 2) )
        //    invalidData(lstate, 2);
		checkType(lstate, T_STRING, 2);

        binding = lua_tostring(lstate, 1);
        keyname = lua_tostring(lstate, 2);
        server = true;
    }

    NetCon *lnetcon = (NetCon *)lua_newuserdata(lstate, sizeof(NetCon));

    // set metatable
    luaL_getmetatable(lstate, metatable_netcon);
    lua_setmetatable(lstate, -2);

    if( !server )
        *lnetcon = Macro::instance()->netOpenCon(NULL, keyname);
    else
        *lnetcon = Macro::instance()->netOpenCon(binding.c_str(), keyname);

    return 1;
}

int netListen(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);

    NetCon *lnetcon;
    lnetcon = (NetCon *)lua_touserdata(lstate, 1);

    int result = Macro::instance()->netListen(*lnetcon);
    lua_pushnumber(lstate, result);

    return 1;
}

int netPollListen(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);

    NetCon *lnetcon;
    lnetcon = (NetCon *)lua_touserdata(lstate, 1);

    NetCon tmpcon = Macro::instance()->netPollListen(*lnetcon);
    if( tmpcon.conn == NULL )
        lua_pushnil(lstate);
    else
    {
        NetCon *lnewcon = (NetCon *)lua_newuserdata(lstate, sizeof(NetCon));
        luaL_getmetatable(lstate, metatable_netcon);
        lua_setmetatable(lstate, -2);
        lnewcon->conn = tmpcon.conn;
        lnewcon->setkeyname(tmpcon.keyname);
    }

    return 1;
}

int netConnect(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);
    //if( !lua_isstring(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_STRING, 2);

    NetCon *lnetcon;
    lnetcon = (NetCon *)lua_touserdata(lstate, 1);
    std::string address = lua_tostring(lstate, 2);

    int result = Macro::instance()->netConnect(*lnetcon, address.c_str());
    lua_pushnumber(lstate, result);

    return 1;
}

int netConnectStatus(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);

    NetCon *lnetcon;
    lnetcon = (NetCon *)lua_touserdata(lstate, 1);

    int result = Macro::instance()->netConnectStatus(*lnetcon);
    lua_pushnumber(lstate, result);

    return 1;
}

int netPollMessages(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);

    NetCon *lnetcon;
    lnetcon = (NetCon *)lua_touserdata(lstate, 1);

    int result = Macro::instance()->netPollMessages(*lnetcon);
    lua_pushboolean(lstate, result);

    return 1;
}

int netGetMessage(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);

    NetCon *lnetcon;
    lnetcon = (NetCon *)lua_touserdata(lstate, 1);

    unsigned int indexcount = 1;
    std::string packetstr = Macro::instance()->netGetMessage(*lnetcon);
    if( packetstr.length() )
    {
        Message packet;
        packet.set_data(packetstr);

        lua_newtable(lstate);

        int dtype = packet.get_next_type();
        while( dtype != P_TYPE_ERROR )
        {
            switch( dtype )
            {
                case P_TYPE_STRING: {
                    std::string str = packet.read_string();
                    lua_pushnumber(lstate, indexcount); // key
                    lua_pushstring(lstate, str.c_str()); // value
                    lua_settable(lstate, -3);
                    indexcount++;
                }
                break;

                case P_TYPE_FLOAT: {
                    double num = packet.read_float();
                    lua_pushnumber(lstate, indexcount); // key
                    lua_pushnumber(lstate, num); // value
                    lua_settable(lstate, -3);
                    indexcount++;
                }
                break;
            }

            dtype = packet.get_next_type();
        }
    }

  return 1;
}

int netSendMessage(lua_State *lstate)
{
    unsigned int argcount = lua_gettop(lstate);

    if( argcount < 1 )
        wrongArgs(lstate);
	checkType(lstate, T_USERDATA, 1);

    NetCon *lnetcon;
    lnetcon = (NetCon *)lua_touserdata(lstate, 1);

    /* NOTE:
        Lua does not differentiate between integers
        and floating point numbers. Because of this,
        all numbers will be considered of type double. */

    Message packet;

    for(unsigned int i = 2; i <= argcount; i++)
    {
        if( lua_isnumber(lstate, i) )
            packet.push_float( lua_tonumber(lstate, i) );
        else if( lua_isstring(lstate, i) )
            packet.push_string( lua_tostring(lstate, i) );
        else
            invalidData(lstate, i);
    }

    int status = 0;

    if( packet.length() )
        status = Macro::instance()->netSendMessage(*lnetcon, packet.c_str(),
            packet.length());

    lua_pushnumber(lstate, status);
    return 1;
}

int netGetAddress(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
		wrongArgs(lstate);
	//if( !lua_isuserdata(lstate, 1) )
	//	invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);

	NetCon *lnetcon;
	lnetcon = (NetCon *)lua_touserdata(lstate, 1);

	char *addr = Macro::instance()->netGetAddress(*lnetcon);
	lua_pushstring(lstate, addr);

	return 1;
}

int netCloseCon(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isuserdata(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_USERDATA, 1);

    NetCon *lnetcon;
    lnetcon = (NetCon *)lua_touserdata(lstate, 1);

	// Do not close unless it is open.
	if( Macro::instance()->netConnectStatus(*lnetcon) > 0 )
		Macro::instance()->netCloseCon(*lnetcon);

    return 0;
}


int newTimer(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    std::string tname = lua_tostring(lstate, 1);

    if( tname.length() < 1 )
        luaL_error(lstate, "Timer name cannot be NULL.\n");

    Macro::instance()->newTimer(tname);

    return 0;
}

int removeTimer(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    std::string tname = lua_tostring(lstate, 1);

    if( tname.length() < 1 )
        luaL_error(lstate, "Timer name cannot be NULL.\n");

    if( !Macro::instance()->removeTimer(tname) )
    {
        std::string err = "Timer not found: \'";
        err += tname;
        err += "\'";
        luaL_error(lstate, err.c_str());
    }

    return 0;
}

int startTimer(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

    std::string tname = lua_tostring(lstate, 1);

    if( tname.length() < 1)
        luaL_error(lstate, "Timer name cannot be NULL.\n");

    double trigger = (double)lua_tonumber(lstate, 2);

    if( !Macro::instance()->startTimer(tname, trigger) )
    {
        std::string err = "Timer not found: \'";
        err += tname;
        err += "\'";
        luaL_error(lstate, err.c_str());
    }

    return 0;
}

int isTriggered(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1))
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    std::string tname = lua_tostring(lstate, 1);

    if( tname.length() < 1)
    luaL_error(lstate, "Timer name cannot be NULL.\n");


    int result = Macro::instance()->isTriggered(tname);

    if( result >= 0 ) {
        lua_pushboolean(lstate, result);
        return 1; }
    else
    {
        std::string err = "Timer not found: \'";
        err += tname;
        err += "\'";
        luaL_error(lstate, err.c_str());
    }

    return 0;
}

int getTime(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    LARGE_INTEGER now = Macro::instance()->getTime();
    unsigned long high, low;
    high = (unsigned long)now.HighPart;
    low = (unsigned long)now.LowPart;

    lua_newtable(lstate);
    luaL_getmetatable(lstate, metatable_int64);
    lua_setmetatable(lstate, -2);

    lua_pushstring(lstate, "high"); //key
    lua_pushnumber(lstate, high); //value
    lua_settable(lstate, -3);

    lua_pushstring(lstate, "low"); //key
    lua_pushnumber(lstate, low); //value
    lua_settable(lstate, -3);

    return 1;
}

int getTimerFrequency(lua_State *lstate)
{
	if( lua_gettop(lstate) != 0 )
		wrongArgs(lstate);

	LARGE_INTEGER frequency = Macro::instance()->getTimerFrequency();
	unsigned long high, low;
	high = (unsigned long)frequency.HighPart;
	low = (unsigned long)frequency.LowPart;

    lua_newtable(lstate);
    luaL_getmetatable(lstate, metatable_int64);
    lua_setmetatable(lstate, -2);

    lua_pushstring(lstate, "high"); //key
    lua_pushnumber(lstate, high); //value
    lua_settable(lstate, -3);

    lua_pushstring(lstate, "low"); //key
    lua_pushnumber(lstate, low); //value
    lua_settable(lstate, -3);

    return 1;
}

int deltaTime(lua_State *lstate)
{
    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !(lua_istable(lstate, 1) || lua_isnumber(lstate, 1)) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_TABLE | T_NUMBER, 1);
    //if( !(lua_istable(lstate, 2) || lua_isnumber(lstate, 2)) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_TABLE | T_NUMBER, 1);

    unsigned long high2, low2, high1, low1;
    LARGE_INTEGER t2, t1;


    // Get info from arg 1
    if( lua_isnumber(lstate, 1) )
    {
        high2 = 0; low2 = (int)lua_tonumber(lstate, 1);
    }
    else
		t2 = lua_toint64(lstate, 1);

    // Get info from arg 2
    if( lua_isnumber(lstate, 2) )
    {
        high1 = 0; low1 = (int)lua_tonumber(lstate, 2);
    }
    else
		t1 = lua_toint64(lstate, 2);


    double difftime = Macro::instance()->deltaTime(t2, t1);
    lua_pushnumber(lstate, difftime);
    return 1;
}

int ipcOpen(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

	int procId = (int)lua_tonumber(lstate, 1);

	if( Macro::instance()->ipcOpen(procId) )
		lua_pushboolean(lstate, true);
	else
		lua_pushboolean(lstate, false);

	return 1;
}

int ipcClose(lua_State *lstate)
{
	if( lua_gettop(lstate) != 0 )
		wrongArgs(lstate);

	Macro::instance()->ipcClose();
	return 0;
}

int ipcSend(lua_State *lstate)
{
	int top = lua_gettop(lstate);
	if( top == 0 )
		wrongArgs(lstate);

	Message out; Message in;

	for(int i = 1; i <= top; i++)
	{
		if( lua_isnumber(lstate, i) )
		{
			out.push_float((double)lua_tonumber(lstate, i));
		}
		else if( lua_isstring(lstate, i) )
		{
			out.push_string((char*)lua_tostring(lstate, i));
		}
		else
			invalidData(lstate, i);
	}

	int success = Macro::instance()->ipcSend(&out, &in);

	// Error occured
	if( !success )
	{
		lua_pushnil(lstate);
		return 1;
	}

	// No data returned
	if( in.get_next_type() == P_TYPE_ERROR || in.length() <= 1 )
	{
		lua_pushnil(lstate);
		return 1;
	}

    printf("Return some data\n");
	// Return some data
	int count = 0;
	int nextType = in.get_next_type();
	while( nextType != P_TYPE_ERROR )
	{
		if( nextType == P_TYPE_FLOAT )
		{
            printf("Pushing number\n");
			lua_pushnumber(lstate, in.read_float());
			count++;
		}
		else if( nextType == P_TYPE_STRING )
		{
            printf("Pushing string\n");
			lua_pushstring(lstate, in.read_string().c_str());
			count++;
		}

        nextType = in.get_next_type();
	}

	return count;
}

int soundPlay(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
		wrongArgs(lstate);

	checkType(lstate, T_USERDATA, 1);
	AudioResource **laudioresource = (AudioResource **)lua_touserdata(lstate, 1);
	Macro::instance()->soundPlay(*laudioresource);

	return 0;
}

int soundStop(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
		wrongArgs(lstate);

	checkType(lstate, T_USERDATA, 1);
	AudioResource* *laudioresource = (AudioResource **)lua_touserdata(lstate, 1);
	Macro::instance()->soundStop(*laudioresource);

	return 0;
}

int soundPause(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
		wrongArgs(lstate);

	checkType(lstate, T_USERDATA, 1);
	AudioResource **laudioresource = (AudioResource **)lua_touserdata(lstate, 1);
	Macro::instance()->soundPause(*laudioresource);

	return 0;
}

int soundLoad(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
		wrongArgs(lstate);
	checkType(lstate, T_STRING, 1);

	char *fname = (char *)lua_tostring(lstate, 1);
	AudioResource *audioresource = Macro::instance()->soundLoad(fname);

	if( audioresource == NULL )
	{
		delete audioresource;
		lua_pushnil(lstate);
		return 1;
	}

	AudioResource **plaudioresource = (AudioResource **)lua_newuserdata(lstate, sizeof(AudioResource *));
	luaL_getmetatable(lstate, metatable_audioresource);
	lua_setmetatable(lstate, -1);

	*plaudioresource = audioresource;
	return 1;
}

int soundSetLooping(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
		wrongArgs(lstate);
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_BOOLEAN | T_NUMBER, 2);

	int loop = (int)lua_toboolean(lstate, 2);

	AudioResource **laudioresource = (AudioResource **)lua_touserdata(lstate, 1);
	Macro::instance()->soundSetLooping(*laudioresource, loop);

	return 0;
}

int soundSetVolume(lua_State *lstate)
{
	if( lua_gettop(lstate) != 2 )
		wrongArgs(lstate);
	checkType(lstate, T_USERDATA, 1);
	checkType(lstate, T_NUMBER, 2);

	float volume = (float)lua_tonumber(lstate, 2);

	AudioResource **laudioresource = (AudioResource **)lua_touserdata(lstate, 1);
	Macro::instance()->soundSetVolume(*laudioresource, volume);

	return 0;
}

int soundGetState(lua_State *lstate)
{
	if( lua_gettop(lstate) != 1 )
		wrongArgs(lstate);
	checkType(lstate, T_USERDATA, 1);

	AudioResource **laudioresource = (AudioResource **)lua_touserdata(lstate, 1);
	ALint state = Macro::instance()->soundGetState(*laudioresource);

	switch( state )
	{
		case AL_PLAYING:
			lua_pushstring(lstate, "playing");
		break;

		case AL_STOPPED:
			lua_pushstring(lstate, "stopped");
		break;

		case AL_INITIAL:
			lua_pushstring(lstate, "initial");
		break;

		case AL_PAUSED:
			lua_pushstring(lstate, "paused");
		break;

		default:
			lua_pushstring(lstate, "unknown");
		break;
	}

	return 1;
}

int clearScreen(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    Macro::instance()->clearScreen();
    return 0;
}

int rest(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    unsigned long utime = (unsigned int)lua_tonumber(lstate, 1);
    Macro::instance()->rest(utime);

    return 0;
}

int setPriority(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int priority = (int)lua_tonumber(lstate, 1);
    if( priority < -1 || priority > 1 )
        luaL_error(lstate, "Invalid data passed to setPriority().");

    Macro::instance()->setPriority(priority);
    return 0;
}

int logMessage(lua_State *lstate)
{
    if( lua_gettop(lstate) < 1 )
        wrongArgs(lstate);
    //if( !lua_isstring(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_STRING, 1);

    std::string msg = (std::string)lua_tostring(lstate, 1);
    Logger::instance()->add("%s", msg.c_str());

    return 0;
}

int logRaw(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !(lua_isstring(lstate, 1) || lua_isnumber(lstate, 1)) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER | T_STRING, 1);

    std::string msg = (std::string)lua_tostring(lstate, 1);
    Logger::instance()->add_raw(msg.c_str());

    return 0;
}

int getVersion(lua_State *lstate)
{
    if( lua_gettop(lstate) != 0 )
        wrongArgs(lstate);

    lua_pushnumber(lstate, VERSION_NUMBER);
    return 1;
}

int setTextColor(lua_State *lstate)
{
	int args = lua_gettop(lstate);
    if( !(args == 1 || args == 2) )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);

    int colorcode = (int)lua_tonumber(lstate, 1);
	int background = 0;

	if( args >= 2 )
	{
		//if( !lua_isnumber(lstate, 2) )
		//	invalidData(lstate, 2);
		checkType(lstate, T_NUMBER, 2);

		background = (int)lua_tonumber(lstate, 2);
	}


    Macro::instance()->setTextColor(colorcode, background);
    return 0;
}

int showWarnings(lua_State *lstate)
{
    if( lua_gettop(lstate) != 1 )
        wrongArgs(lstate);
    //if( !lua_isboolean(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_BOOLEAN, 1);

    int enabled = (int)lua_tonumber(lstate, 1);
    Macro::instance()->showWarnings(enabled);
    return 0;
}


int bitAnd(lua_State *lstate)
{
	DEPRECATED()

    if( lua_gettop(lstate) < 2 )
        wrongArgs(lstate);

    unsigned int argcount = lua_gettop(lstate);
    for(unsigned int i = 1; i <= argcount; i++)
    {
        //if( !lua_isnumber(lstate, i) )
        //    invalidData(lstate, i);
		checkType(lstate, T_NUMBER, i);
    }

    unsigned int val = (unsigned int)lua_tonumber(lstate, 1);
    for(unsigned int i = 2; i <= argcount; i++)
    {
        unsigned int val2 = (unsigned int)lua_tonumber(lstate, i);
        val = Macro::instance()->bitAnd(val, val2);
    }

    lua_pushboolean(lstate, val);
    return 1;
}

int bitOr(lua_State *lstate)
{
	DEPRECATED()

    if( lua_gettop(lstate) < 2 )
        wrongArgs(lstate);

    unsigned int argcount = lua_gettop(lstate);

    for(unsigned int i = 1; i <= argcount; i++)
    {
        //if( !lua_isnumber(lstate, i) )
        //invalidData(lstate, i);
		checkType(lstate, T_NUMBER, i);
    }

    unsigned int val = 0;
    for(unsigned int i = 1; i <= argcount; i++)
    {
        unsigned int val2 = (unsigned int)lua_tonumber(lstate, i);
        val = Macro::instance()->bitOr(val, val2);
    }

    lua_pushnumber(lstate, val);
    return 1;
}

int bitLShift(lua_State *lstate)
{
	DEPRECATED()

    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

  unsigned int num1 = (unsigned int)lua_tonumber(lstate, 1);
  unsigned int num2 = (unsigned int)lua_tonumber(lstate, 2);

  lua_pushnumber(lstate, Macro::instance()->bitLShift(num1, num2));
  return 1;
}

int bitRShift(lua_State *lstate)
{
	DEPRECATED()

    if( lua_gettop(lstate) != 2 )
        wrongArgs(lstate);
    //if( !lua_isnumber(lstate, 1) )
    //    invalidData(lstate, 1);
	checkType(lstate, T_NUMBER, 1);
    //if( !lua_isnumber(lstate, 2) )
    //    invalidData(lstate, 2);
	checkType(lstate, T_NUMBER, 2);

  unsigned int num1 = (unsigned int)lua_tonumber(lstate, 1);
  unsigned int num2 = (unsigned int)lua_tonumber(lstate, 2);

  lua_pushnumber(lstate, Macro::instance()->bitRShift(num1, num2));
  return 1;
}

int sha1_hash(lua_State *lstate)
{
	int args = lua_gettop(lstate);
	if( args != 1 && args != 2 )
		wrongArgs(lstate);

	checkType(lstate, T_STRING, 1);
	if( args > 1 )
		checkType(lstate, T_NIL | T_BOOLEAN, 2);

	char *instr = (char*)lua_tostring(lstate, 1);
	bool raw = false;

	if( lua_isboolean(lstate, 2) )
		raw = lua_toboolean(lstate, 2);

	unsigned char hash[20];
	char hexstring[41];
	sha1::calc(instr, strlen(instr), hash);

	if( raw )
		lua_pushstring(lstate, (char *)hash);
	else
	{
		sha1::toHexString(hash, hexstring);
		lua_pushstring(lstate, (char *)hexstring);
	}

	return 1;
}
